#pragma once

using namespace System;
using namespace System::Runtime::InteropServices;

#define VPX_CODEC_DISABLE_COMPAT 1
#include<vpx/vpx_image.h>

namespace NVP8 
{
	public ref class VPXImage
	{
	public:
		VPXImage()
		{
		}

		VPXImage(int width, int height)
		{
			AllocateI420(width, height);
		}

		VPXImage(vpx_image_t* image)
		{
			imageData = image;
			allocatedImageData = NULL;
		}

		VPXImage^ Init(vpx_image_t* image)
		{
			imageData = image;
			allocatedImageData = NULL;
			return this;
		}

		VPXImage^ Init(array<Byte>^ data)
		{
			pin_ptr<unsigned char> dataArray = &data[0];
			return Init(dataArray);
		}

		VPXImage^ Init(unsigned char* data)
		{
			int toRead = imageData->d_w * imageData->d_h * 3 / 2;
			memcpy(imageData->planes[0], data, toRead);
			return this;
		}
		
		int GetWidth()
		{
			return imageData->d_w;
		}

		int GetHeight()
		{
			return imageData->d_h;
		}

		void WriteTo(array<Byte>^ target, int offset)
		{
			int requiredBytes = imageData->d_w * imageData->d_h * 3 / 2;
			if (target->Length - offset < requiredBytes)
				throw gcnew ArgumentOutOfRangeException("target");
			pin_ptr<unsigned char> targetArray = &target[offset];
			memcpy(targetArray, imageData->planes[0], requiredBytes);
		}

		!VPXImage()
		{
			if (allocatedImageData != NULL)
			{	
				vpx_img_free(allocatedImageData);
				delete allocatedImageData;
				allocatedImageData = NULL;
			}
			imageData = NULL;
		}

		~VPXImage()
		{
			this->!VPXImage();
		}

		const vpx_image_t* GetImageData()
		{
			return imageData;
		}

	private:
		void AllocateI420(int width, int height)
		{
			allocatedImageData = new vpx_image_t();
			vpx_img_alloc(allocatedImageData, VPX_IMG_FMT_I420, width, height, 1);
			imageData = allocatedImageData;
		}

		vpx_image_t* imageData;
		vpx_image_t* allocatedImageData;
	};
}